﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CoyoEden.Providers;
using System.ComponentModel;

namespace CoyoEden.Models
{
	/// <summary>
	/// A topic in a certain community
	/// </summary>
	[Serializable]
	public class Topic:BusinessBase<Topic,int>,IComparable<Topic>,IPublishable
	{
		#region .ctor
		public Topic() {
			base.Id = -1;
			_Title = "";
			_Description = "";
			_Content = "";
			_Comments = new List<Comment>();
			_Communities = new StateList<Community>();
			_Tags = new StateList<string>();
			DateCreated = DateTime.Now;
			_IsCommentEnabled = true;
			_IsPublished = true;
			_IsValuable = false;
		}
		#endregion

		#region Member variables
		private string _Title;
		public string Title {
			get { return _Title; }
			set {
				if (_Title != value) {
					MarkChanged("Title");
					_Title = value;
				}
			}
		}
		private string _Description;
		public string Description {
			get { return _Description; }
			set {
				if (_Description != value) {
					MarkChanged("Description");
					_Description = value;
				}
			}
		}
		private string _Content;
		public string Content {
			get {
				return _Content;
			}
			set {
				if (_Content != value) {
					MarkChanged("Content");
					_Content = value;
				}
			}
		}

		private readonly List<Comment> _Comments;
		public List<Comment> Comments {
			get { return _Comments; }
		}
		/// <summary>
		/// A collection of Approved comments for the topic sorted by date.
		/// </summary>
		public List<Comment> ApprovedComments
		{
			get
			{
				return _Comments.FindAll(c=>c.IsApproved);
			}
		}

		/// <summary>
		/// A collection of comments waiting for approval for the topic, sorted by date.
		/// </summary>
		public List<Comment> NotApprovedComments
		{
			get
			{
				return _Comments.FindAll(c=>!c.IsApproved);
			}
		}

		private StateList<Community> _Communities;
		public StateList<Community> Communities {
			get {
				return _Communities;
			}
		}
		private StateList<string> _Tags;
		/// <summary>
		/// An unsorted collection of tags.
		/// </summary>
		public StateList<string> Tags
		{
			get { return _Tags; }
		}

		private bool _IsCommentEnabled;
		public bool IsCommentEnabled {
			get {
				return _IsCommentEnabled;
			}
			set {
				if (_IsCommentEnabled != value) {
					MarkChanged("IsCommentEnabled");
					_IsCommentEnabled = value;
				}
			}
		}
		private bool _IsPublished;
		public bool IsPublished {
			get {
				return _IsPublished;
			}
			set {
				if (_IsPublished != value) {
					MarkChanged("IsPublished");
					_IsPublished = value;
				}
			}
		}
		private bool _IsValuable;
		public bool IsValuable {
			get {
				return _IsValuable;
			}
			set {
				if (_IsValuable != value) {
					MarkChanged("IsValuable");
					_IsValuable = value;
				}
			}
		}
		private bool _IsApproved;
		public bool IsApproved {
			get {
				return _IsApproved;
			}
			set {
				if (_IsApproved != value) {
					MarkChanged("IsApproved");
					_IsApproved = value;
				}
			}
		}
		private string _Icon;
		public string Icon {
			get {
				return _Icon;
			}
			set {
				if (_Icon != value) {
					MarkChanged("Icon");
					_Icon = value;
				}
			}
		}
		private string _Author;
		/// <summary>
		/// Author profile,in Json format
		/// </summary>
		public string Author
		{
			get {
				if (!_AuthorProfile.Equals(null)) {
					_Author = Utils.ToStr<SimpleAuthorProfile>(_AuthorProfile);
				}
				return _Author;
			}
			set {
				if (_Author != value) {
					MarkChanged("Author");
					_Author = value;
				}
			}
		}
		private SimpleAuthorProfile _AuthorProfile;
		public SimpleAuthorProfile AuthorProfile {
			get {
				if (!string.IsNullOrEmpty(_Author)) {
					Utils.ToObject<SimpleAuthorProfile>(_Author,out _AuthorProfile);
				}
				return _AuthorProfile;
			}
			set {
				if (!_AuthorProfile.Equals( value)) {
					MarkChanged("Author");
					_AuthorProfile = value;
				}
			}
		}
		private static object _SyncRoot = new object();
		private static List<Topic> _Topics;
		/// <summary>
		/// A sorted collection of all posts in the blog.
		/// Sorted by date.
		/// </summary>
		public static List<Topic> Topics
		{
			get
			{
				if (_Topics == null)
				{
					lock (_SyncRoot)
					{
						if (_Topics == null)
						{
							_Topics = PortalService.FillTopics();
							_Topics.TrimExcess();
						}
					}
				}

				return _Topics;
			}
		}
		#endregion

		#region BusinessBase members
		/// <summary>
		/// Gets if the Post have been changed.
		/// </summary>
		public override bool IsChanged
		{
			get
			{
				if (base.IsChanged)
					return true;

				if (Communities.IsChanged || Tags.IsChanged)
					return true;

				return false;
			}
		}
		protected override void ValidationRules()
		{
			AddRule("Content","内容不能为空",ContentRule());
		}

		protected override Topic DataSelect(int id)
		{
			return PortalService.SelectTopic(id);
		}

		protected override void DataUpdate()
		{
			PortalService.UpdateTopic(this);
		}

		protected override void DataInsert()
		{
			PortalService.InsertTopic(this);
			if (this.IsNew) {
				Topics.Add(this);
				Topics.Sort();
			}
		}

		protected override void DataDelete()
		{
			PortalService.DeleteTopic(this);
			if (Topics.Contains(this)) {
				Topics.Remove(this);
				Dispose();
			}
		}
		public override string ToString()
		{
			return string.Format("{0}[{1}]",Title,Id);
		}
		public override void MarkOld()
		{
			_Communities.MarkOld();
			base.MarkOld();
		}
		public new static Topic Load(int id) {
			Topic instance = new Topic();
			instance = instance.DataSelect(id);
			if (instance != null)
			{
				instance.Id = id;
				instance.MarkOld();
				return instance;
			}
			return null;

		}
		#endregion

		#region IComparable<Topic> Members

		public int CompareTo(Topic other)
		{
			return other.DateCreated.CompareTo(this.DateCreated);
		}

		#endregion

		#region IPublishable Members

		public string RelativeLink
		{
			get {
				var link = string.Format("{0}topic/{1}.aspx",Utils.RelativeWebRoot,Id);
				return link;
			}
		}

		public Uri AbsoluteLink
		{
			get {
				return Utils.ConvertToAbsolute(RelativeLink);
			}
		}

		/// <summary>
		/// We use Communities to organize topics.
		/// </summary>
		public StateList<Category> Categories
		{
			get { return null; }
		}

		public bool IsVisible
		{
			get
			{
				if (IsAuthenticated || IsPublished && DateCreated <= DateTime.Now.AddHours(PortalSettings.Instance.Timezone))
					return true;

				return false;
			}
		}

		#endregion

		#region events
		/// <summary>
		/// Occurs before a new comment is added.
		/// </summary>
		public static event EventHandler<CancelEventArgs> AddingComment;
		/// <summary>
		/// Raises the event in a safe way
		/// </summary>
		protected virtual void OnAddingComment(Comment comment, CancelEventArgs e)
		{
			if (AddingComment != null)
			{
				AddingComment(comment, e);
			}
		}

		/// <summary>
		/// Occurs when a comment is added.
		/// </summary>
		public static event EventHandler<EventArgs> CommentAdded;
		/// <summary>
		/// Raises the event in a safe way
		/// </summary>
		protected virtual void OnCommentAdded(Comment comment)
		{
			if (CommentAdded != null)
			{
				CommentAdded(comment, new EventArgs());
			}
		}

		/// <summary>
		/// Occurs before comment is removed.
		/// </summary>
		public static event EventHandler<CancelEventArgs> RemovingComment;
		/// <summary>
		/// Raises the event in a safe way
		/// </summary>
		protected virtual void OnRemovingComment(Comment comment, CancelEventArgs e)
		{
			if (RemovingComment != null)
			{
				RemovingComment(comment, e);
			}
		}

		/// <summary>
		/// Occurs when a comment has been removed.
		/// </summary>
		public static event EventHandler<EventArgs> CommentRemoved;
		/// <summary>
		/// Raises the event in a safe way
		/// </summary>
		protected virtual void OnCommentRemoved(Comment comment)
		{
			if (CommentRemoved != null)
			{
				CommentRemoved(comment, new EventArgs());
			}
		}
		/// <summary>
		/// Occurs when the post is being served to the output stream.
		/// </summary>
		public static event EventHandler<ServingEventArgs> Serving;
		/// <summary>
		/// Raises the event in a safe way
		/// </summary>
		public static void OnServing(Topic topic, ServingEventArgs arg)
		{
			if (Serving != null)
			{
				Serving(topic, arg);
			}
		}

		/// <summary>
		/// Raises the Serving event
		/// </summary>
		public void OnServing(ServingEventArgs eventArgs)
		{
			if (Serving != null)
			{
				Serving(this, eventArgs);
			}
		}
		#endregion

		#region methods
		/// <summary>
		/// Returns all topics in the specified community
		/// </summary>
		public static List<Topic> GetTopicsByCommunity(int id)
		{
			List<Topic> col = Topics.FindAll(t=>t.Communities.Contains(Community.GetCommunity(id)));

			col.Sort();
			col.TrimExcess();
			return col;
		}
		public static Topic GetTopic(string id)
		{
			var retVal = Topics.Single(item => item.Id.ToString() == id);
			return retVal;
		}
		/// <summary>
		/// Returns all posts tagged with the specified tag.
		/// </summary>
		public static List<Topic> GetTopicsByTag(string tag)
		{
			List<Topic> list =Topics.FindAll(item=>item.Tags.Contains(tag));
			list.TrimExcess();
			return list;
		}

		/// <summary>
		/// Adds a comment to the collection and saves the post.
		/// </summary>
		/// <param name="comment">The comment to add to the post.</param>
		public void AddComment(Comment comment)
		{
			CancelEventArgs e = new CancelEventArgs();
			OnAddingComment(comment, e);
			if (!e.Cancel)
			{
				Comments.Add(comment);
				DataUpdate();
				OnCommentAdded(comment);
			}
		}
		/// <summary>
		/// Removes a comment from the collection and saves the post.
		/// </summary>
		/// <param name="comment">The comment to remove from the post.</param>
		public void RemoveComment(Comment comment)
		{
			CancelEventArgs e = new CancelEventArgs();
			OnRemovingComment(comment, e);
			if (!e.Cancel)
			{
				Comments.Remove(comment);
				DataUpdate();
				OnCommentRemoved(comment);
				comment = null;
			}
		}

		/// <summary>
		/// Approves a Comment for publication.
		/// </summary>
		/// <param name="comment">The Comment to approve</param>
		public void ApproveComment(Comment comment)
		{
			CancelEventArgs e = new CancelEventArgs();
			Comment.OnApproving(comment, e);
			if (!e.Cancel)
			{
				int inx = Comments.IndexOf(comment);
				Comments[inx].IsApproved = true;
				this.DateModified = comment.DateCreated;
				this.DataUpdate();
				Comment.OnApproved(comment);
				//SendNotifications(comment);
			}
		}

		/// <summary>
		/// Approves all the comments in a post.  Included to save time on the approval process.
		/// </summary>
		public void ApproveAllComments()
		{
			foreach (Comment comment in Comments)
			{
				ApproveComment(comment);
			}
		}
		#endregion

		#region business rules
		private bool ContentRule() {
			bool isBroken = false;
			if (string.IsNullOrEmpty(_Content))
			{
				isBroken = true;
			}
			return isBroken;
		}
		#endregion
	}
}
